#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"
#include "freertos/ringbuf.h"

#include "Rs485Interface.h"

//need include your board configure and communication protocol parsing file
#include "prase.h"
#include "boardConfig.h"


#define BUF_SIZE (1023)



static const char *TAG = "rs485 task";
static const char *TAG_485_1 = "rs485 1 event";
static const char *TAG_485_2 = "rs485 2 event";

static bool waitBusIdleMaxTime(int delayMs);
static void waitBusIdle(void);

typedef struct{
    uint16_t RxBufSize;
    uint16_t TxBufSize;
    uint16_t EventQueueSize;
    QueueHandle_t * EventHandle;
    uint16_t InterruptFlag;
}_uartDriverConfig_t;

typedef struct{
    int16_t    txpin;
    int16_t    rxpin;
    int16_t    rtspin;
    int16_t    ctspin;
}_uartPinConfig_t;

typedef struct{
    TaskFunction_t _task;
    const char *_taskName;
    int Priority;
}_uartEventTaskConfig_t;

typedef struct{
    uart_port_t uart_port;
    uart_config_t uart_config;
    _uartDriverConfig_t _uartDriverConfig;
    _uartPinConfig_t _uartPinConfig;
    _uartEventTaskConfig_t _uartEventTaskConfig;
    RingbufHandle_t uart_rx_ring_buf;
    Rs485AnalyzeFunc_t praseAnalyze;
}_uartConfig_t;

typedef enum{
#ifdef USE_UART1_WITH_RS485
    _uart1 = 0,
#endif
#ifdef USE_UART2_WITH_RS485
    _uart2,
#endif
    _uartnum,
}useUart_t;

typedef enum{
    _rs485_1 = 0,
#ifdef USE_UART2_WITH_RS485
    _rs485_2,
#endif
    _rs485num,
}use485_t;

typedef struct{
    uart_port_t port;
    char buf[BUF_SIZE];
    size_t size;
}uartRxData_t;


QueueHandle_t uart1_queue;
QueueHandle_t uart2_queue;

void uart1_event_task(void *pvParameters);
void uart2_event_task(void *pvParameters);

static _uartConfig_t UseUart[_uartnum] = {
    {
        #ifdef USE_UART1_WITH_RS485
        RS4851_UARTNUM,
        {
            .baud_rate = 115200,
            .data_bits = UART_DATA_8_BITS,
            .parity = UART_PARITY_DISABLE,
            .stop_bits = UART_STOP_BITS_1,
            .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
            .rx_flow_ctrl_thresh = 512,
            .source_clk = UART_SCLK_APB
        },
        {
            BUF_SIZE,
            0,
            10,
            &uart1_queue,
            0
        },
        {
            RS485_1TXPIN, 
            RS485_1RXPIN, 
            UART_PIN_NO_CHANGE,  // RTS
            UART_PIN_NO_CHANGE
        },
        {
            uart1_event_task,
            "uart1_event",
            4
        },
        NULL,
        NULL
    },
    #endif
    #ifdef USE_UART2_WITH_RS485
    {
        RS4852_UARTNUM, 
        {
            .baud_rate = 115200,
            .data_bits = UART_DATA_8_BITS,
            .parity = UART_PARITY_DISABLE,
            .stop_bits = UART_STOP_BITS_1,
            .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
            .rx_flow_ctrl_thresh = 512,
            .source_clk = UART_SCLK_APB
        },
        {
            BUF_SIZE,
            0,
            10,
            &uart2_queue,
            0
        },
        {
            RS485_2TXPIN, 
            RS485_2RXPIN, 
            UART_PIN_NO_CHANGE,  // RTS
            UART_PIN_NO_CHANGE
        },
        {
            uart2_event_task,
            "uart2_event",
            4
        },
        NULL,
        NULL
    }
    #endif
};

static uint16_t rs485DEPin[_rs485num] = {
#ifdef USE_UART1_WITH_RS485
                                            RS485_1DEPIN, 
#endif
#ifdef USE_UART2_WITH_RS485
                                            RS485_2DEPIN
#endif
                                        };
static QueueHandle_t uartRxDataQueue;

bool WaitReply = 0;

static void Rs485SetTxState(uint8_t Rs485C);
static void Rs485SetRxState(uint8_t Rs485C);

static void uart_init(void) 
{
    for (uint8_t i = 0; i < _uartnum; i++)
    {
        ESP_ERROR_CHECK(uart_param_config(UseUart[i].uart_port, &UseUart[i].uart_config));
        ESP_ERROR_CHECK(uart_set_pin(
                                        UseUart[i].uart_port, 
                                        UseUart[i]._uartPinConfig.txpin, 
                                        UseUart[i]._uartPinConfig.rxpin, 
                                        UseUart[i]._uartPinConfig.rtspin,  // RTS
                                        UseUart[i]._uartPinConfig.ctspin   // CTS
                                    ));
        ESP_ERROR_CHECK(uart_driver_install(
                                                UseUart[i].uart_port, 
                                                UseUart[i]._uartDriverConfig.RxBufSize,             // 接收缓冲区大小
                                                UseUart[i]._uartDriverConfig.TxBufSize,             // 发送缓冲区大小
                                                UseUart[i]._uartDriverConfig.EventQueueSize,        // 事件队列大小
                                                UseUart[i]._uartDriverConfig.EventHandle,           // 事件队列句柄
                                                UseUart[i]._uartDriverConfig.InterruptFlag          // 分配中断标志
                                            ));

        uart_set_rx_full_threshold(UseUart[i].uart_port, (BUF_SIZE + 1) / 2 - 2); // 设置满阈值
        uart_set_rx_timeout(UseUart[i].uart_port, 100);

        UseUart[i].uart_rx_ring_buf = xRingbufferCreate(BUF_SIZE, RINGBUF_TYPE_BYTEBUF);
        if (UseUart[i].uart_rx_ring_buf == NULL) 
        {
            ESP_LOGE("UART", "Failed to create ring buffer");
        }

        uart_pattern_queue_reset(UseUart[i].uart_port, UseUart[i]._uartDriverConfig.EventQueueSize);
        xTaskCreate(UseUart[i]._uartEventTaskConfig._task, UseUart[i]._uartEventTaskConfig._taskName, 3072, NULL, UseUart->_uartEventTaskConfig.Priority, NULL);
    }
}

static void Rs485_Init(void)
{
    for (uint8_t i = 0; i < _rs485num; i++)
    {
        gpio_reset_pin(rs485DEPin[i]);  // 可选，重置引脚
        gpio_set_direction(rs485DEPin[i], GPIO_MODE_OUTPUT);
        Rs485SetRxState(rs485DEPin[i]);  // 初始设为低电平

        // Rs485SetTxState(rs485DEPin[i]);  // 初始设为低电平
    }
}

static void Rs485SetRxState(uint8_t Rs485C)
{
     gpio_set_level(Rs485C, 0);
}

static void Rs485SetTxState(uint8_t Rs485C)
{
     gpio_set_level(Rs485C, 1);
}
#include "esp_timer.h"
void Rs485RegisterPraseAnalyze(Rs485AnalyzeFunc_t func, uint32_t uartNum)
{
    if(uartNum < _uartnum)
    {
        UseUart->praseAnalyze = func;
    }
}

bool Rs485SendData(uint8_t Rs485C, uart_port_t uart_num, const void *src, size_t size, bool needWaitReply)
{
    int cnt = 0;

    while(1)
    {
        if (WaitReply == 0)
        {
            Rs485SetTxState(Rs485C);
            vTaskDelay(pdMS_TO_TICKS(1));
            uart_write_bytes(uart_num, src, size);
            uart_wait_tx_done(uart_num, portMAX_DELAY);
            Rs485SetRxState(Rs485C);
            if(needWaitReply)
            {
                WaitReply = 1;
            }
            // ESP_LOGI(TAG_485_1, "rs4851 send time is:%lu", xTaskGetTickCount());
            return 1;
        }
        if(cnt++ > 500)
        {
            // WaitReply = 0;
            // ESP_LOGI(TAG, "rs485 bus blocked for too long\r\n");
            return 0;
        }
        vTaskDelay(pdMS_TO_TICKS(2));
    }
}

void sendRs485Data(TimerHandle_t xTimer)
{
    Rs485SendData(RS485_1DEPIN, RS4851_UARTNUM, "probe release\r\n", strlen("probe release\r\n"), 0);
}

extern TaskHandle_t PosTask;
extern double currentMotorPos[8];
void Rs485Interface_task(void *pvParameters) 
{
    char *rs485_1buf;
    size_t rs485_1_size;
    char buffer1[BUF_SIZE] = {0};
    char sendBuf[255] = {0};
    size_t sendSize = 0;
    uart_init();
    Rs485_Init();

    //need register your prase function
    Rs485RegisterPraseAnalyze(prase, _uart1);

    vTaskDelay(pdMS_TO_TICKS(1000));
    TimerHandle_t testTimer = xTimerCreate("testTimer", pdMS_TO_TICKS(1000), 1, NULL, sendRs485Data);
	xTimerStart(testTimer,portMAX_DELAY);
    while(1)
    {
        rs485_1buf = (char *)xRingbufferReceive(UseUart[0].uart_rx_ring_buf, &rs485_1_size, 0);
        if(rs485_1buf != NULL) {
            if(UseUart[0].praseAnalyze != NULL)
            {
                if(UseUart[0].praseAnalyze(rs485_1buf, sendBuf, &sendSize))
                {
                    Rs485SendData(RS485_1DEPIN, RS4851_UARTNUM, sendBuf, sendSize, 0);
                }
            }
            vRingbufferReturnItem(UseUart[0].uart_rx_ring_buf, rs485_1buf);
        }
        vTaskDelay(20);
    }
}

#ifdef USE_UART1_WITH_RS485
void uart1_event_task(void *pvParameters) 
{
    uart_event_t event;
    uint8_t dma_buffer[BUF_SIZE] = {0};
    size_t buffered_size;
    for (;;) 
    {
        if (xQueueReceive(uart1_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
            switch (event.type) {
            case UART_DATA:
                uart_get_buffered_data_len(UseUart[0].uart_port, &buffered_size);
                // 从UART读取数据
                int len = uart_read_bytes(UseUart[0].uart_port, dma_buffer, buffered_size, pdMS_TO_TICKS(100));
                
                if (len > 0) 
                {
                    // 将数据存入Ring Buffer
                    // uart_write_bytes(UART_NUM_0, dma_buffer, len);
                    // ESP_LOGI(TAG_485_1, "%s", dma_buffer);
                    BaseType_t res = xRingbufferSend(UseUart[0].uart_rx_ring_buf, dma_buffer, len, pdMS_TO_TICKS(100));
                    WaitReply = 0;
                    memset(dma_buffer, 0, sizeof(dma_buffer));
                    // ESP_LOGI(TAG_485_1, "have data from 485_1");
                    if (res != pdTRUE) {
                        ESP_LOGW("UART", "Ring buffer full, dropped %d bytes", len);
                    } else {
                        // 通知其他任务有新数据到达
                        // xTaskNotifyGive(data_process_task_handle);
                    }
                }
                break;
                        // Event of HW FIFO overflow detected
            case UART_FIFO_OVF:
                ESP_LOGI(TAG_485_1, "hw fifo overflow");
                uart_flush_input(UseUart[0].uart_port);
                xQueueReset(uart1_queue);
                break;
            //Event of UART ring buffer full
            case UART_BUFFER_FULL:
                ESP_LOGI(TAG_485_1, "ring buffer full");
                uart_flush_input(UseUart[0].uart_port);
                xQueueReset(uart1_queue);
                break;
            default:
                ESP_LOGI(TAG_485_1, "uart event type: %d", event.type);
                break;
            }
        }
    }
    vTaskDelete(NULL);
}
#endif

#ifdef USE_UART2_WITH_RS485
void uart2_event_task(void *pvParameters) 
{
    uart_event_t event;
    uartRxData_t uartRxData;
    for (;;) 
    {
        if (xQueueReceive(uart2_queue, (void *)&event, (TickType_t)portMAX_DELAY)) 
        {
        //     bzero(uartRxData.buf, BUF_SIZE);
        //     switch (event.type) {
        //     case UART_DATA:
        //         uart_read_bytes(UseUart[1].uart_port, uartRxData.buf, event.size, portMAX_DELAY);
        //         uartRxData.size = event.size;
        //         uartRxData.port = UseUart[1].uart_port;
        //         xQueueSend(uartRxDataQueue, &uartRxData, portMAX_DELAY);
        //         break;
        //     // Event of HW FIFO overflow detected
        //     case UART_FIFO_OVF:
        //         ESP_LOGI(TAG_485_1, "hw fifo overflow");
        //         uart_flush_input(UseUart[1].uart_port);
        //         xQueueReset(uart2_queue);
        //         break;
        //     //Event of UART ring buffer full
        //     case UART_BUFFER_FULL:
        //         ESP_LOGI(TAG_485_1, "ring buffer full");
        //         uart_flush_input(UseUart[1].uart_port);
        //         xQueueReset(uart2_queue);
        //         break;
        //     default:
        //         ESP_LOGI(TAG_485_2, "uart event type: %d", event.type);
        //         break;
        //     }
        }
    }
    vTaskDelete(NULL);
}
#endif

static void waitBusIdle(void)
{
    while(1)
    {
        //todo:获取总线状态
        //if()
        {
            return;
        }
         vTaskDelay(pdMS_TO_TICKS(3));
    }
}

static bool waitBusIdleMaxTime(int delayMs)
{
    const int delayTim = 3;
    int cnt = 0;
    while(1)
    {
        //todo:获取总线状态
        //if()
        {
            return 1;
        }
        if((cnt * delayTim) > delayMs)
        {
            return 0;
        }
         vTaskDelay(pdMS_TO_TICKS(delayTim));
        cnt++;    
    }
}